#include<gtest/gtest.h>

#include<string/spw_string.h>
#include <utility/spw_move_in.h>

using namespace spwstd;
using namespace spwstd::spwstr;

TEST(StringTest, Con) {
    String s;
    EXPECT_TRUE(s.Size() == 0);
    EXPECT_STREQ(s.Data(), "");

    String s1("1234567890abcde");
    EXPECT_TRUE(s1.Size() == 15);
    EXPECT_STREQ(s1.Data(), "1234567890abcde");

    String s2("1234567890abcdef");
    EXPECT_STREQ(s2.Data(), "1234567890abcdef");
    EXPECT_TRUE(s2.Size() == 16);

    String s3(s1);
    EXPECT_STREQ(s3.Data(), "1234567890abcde");
    EXPECT_TRUE(s3.Size() == 15);

    String s4(s2);
    EXPECT_TRUE(s4.Size() == 16);
    EXPECT_STREQ(s4.Data(), "1234567890abcdef");

    String s66(s4.Begin(), s4.End());
    EXPECT_TRUE(s66.Size() == 16);
    EXPECT_STREQ(s66.Data(), "1234567890abcdef");

    // 移动
    String s9(spwuti::move(s66));
    EXPECT_STREQ(s9.Data(), "1234567890abcdef");
    EXPECT_TRUE(s9.Size() == 16);
    String s0(spwuti::move(s4));
    EXPECT_STREQ(s0.Data(), "1234567890abcdef");
    EXPECT_TRUE(s0.Size() == 16);

    String ss({'1','2','3'});
    EXPECT_STREQ(ss.Data(), "123");
    EXPECT_TRUE(ss.Size() == 3);
}

TEST(StringTest, operator) {
    // operator=
    String s0("1234567");
    String s1("1234567890abcdef");
    s1 = s0;
    EXPECT_STREQ(s1.Data(), "1234567");
    EXPECT_TRUE(s1.Size() == 7);
    EXPECT_TRUE(s1.Capacity() == 16);

    s0 = "a";
    EXPECT_STREQ(s0.Data(), "a");
    EXPECT_TRUE(s0.Size() == 1);
    EXPECT_TRUE(s0.Capacity() == 15);

    s0 = "123456";
    EXPECT_STREQ(s0.Data(), "123456");
    EXPECT_TRUE(s0.Size() == 6);
    EXPECT_TRUE(s0.Capacity() == 15);

    s1 = {'1','2','3'};
    EXPECT_STREQ(s1.Data(), "123");
    EXPECT_TRUE(s1.Size() == 3);
    EXPECT_TRUE(s1.Capacity() == 16);

    s1 = spwuti::move(s0);
    EXPECT_STREQ(s1.Data(), "123456");
    EXPECT_TRUE(s1.Size() == 6);
    EXPECT_TRUE(s1.Capacity() == 15);

    //operator[]
    s1[2] = 'a';
    EXPECT_STREQ(s1.Data(), "12a456");
    const String s2 = "zxcvb";
    testing::StaticAssertTypeEq<decltype(s2[2]), const char&>();

    //at
    s1.At(2) = 'b';
    EXPECT_STREQ(s1.Data(), "12b456");
    testing::StaticAssertTypeEq<decltype(s2.At(2)), const char&>();

    EXPECT_THROW({s1[7];}, spwexcept::OutOfRange);
    EXPECT_THROW({s1.At(7);}, spwexcept::OutOfRange);
}


TEST(StringTest, modfiy) {
    // assign
    String s1("1234567890abcdef");
    String s0("0987");

    s1.Assign(s0);
    EXPECT_STREQ(s1.Data(), "0987");
    EXPECT_TRUE(s1.Size() == 4);
    EXPECT_TRUE(s1.Capacity() == 16);

    s0.Assign("1234567890abcdef");
    EXPECT_STREQ(s0.Data(), "1234567890abcdef");
    EXPECT_TRUE(s0.Size() == 16);
    EXPECT_TRUE(s0.Capacity() == 16);

    s1.Assign(spwuti::move(s0));
    EXPECT_STREQ(s1.Data(), "1234567890abcdef");
    EXPECT_TRUE(s1.Size() == 16);
    EXPECT_TRUE(s1.Capacity() == 16);

    s1.Assign({'1','2','3'});
    EXPECT_STREQ(s1.Data(), "123");
    EXPECT_TRUE(s1.Size() == 3);
    EXPECT_TRUE(s1.Capacity() == 16);

    // 追加append, operator+=
    s1.Append("4567890");
    EXPECT_STREQ(s1.Data(), "1234567890");
    EXPECT_TRUE(s1.Size() == 10);
    EXPECT_TRUE(s1.Capacity() == 16);

    String ss("abcdefghi");
    s1.Append(ss, 0, 6);
    EXPECT_STREQ(s1.Data(), "1234567890abcdef");
    EXPECT_TRUE(s1.Size() == 16);
    EXPECT_TRUE(s1.Capacity() == 16);

    s1.Append(2, 'a');
    EXPECT_STREQ(s1.Data(), "1234567890abcdefaa") << s1.Data();
    EXPECT_TRUE(s1.Size() == 18) << s1.Size();
    EXPECT_TRUE(s1.Capacity() == 32) << s1.Capacity();

    s1 = "123";
    s1.Reserve();
    EXPECT_STREQ(s1.Data(), "123");
    EXPECT_TRUE(s1.Size() == 3);
    EXPECT_TRUE(s1.Capacity() == 15);

    s1 += "4567890";
    EXPECT_STREQ(s1.Data(), "1234567890");
    EXPECT_TRUE(s1.Size() == 10);
    EXPECT_TRUE(s1.Capacity() == 15);

    String ss2("abcdefghi");
    s1 += ss2;
    EXPECT_STREQ(s1.Data(), "1234567890abcdefghi");
    EXPECT_TRUE(s1.Size() == 19);
    EXPECT_TRUE(s1.Capacity() == 30) << s1.Capacity();

    s1 += "a";
    EXPECT_STREQ(s1.Data(), "1234567890abcdefghia");
    EXPECT_TRUE(s1.Size() == 20) << s1.Size();
    EXPECT_TRUE(s1.Capacity() == 30);

    // 移除erase
    s1.Erase(4, 6);
    EXPECT_STREQ(s1.Data(), "1234abcdefghia") << s1.Data();
    EXPECT_TRUE(s1.Size() == 14) << s1.Size();
    EXPECT_TRUE(s1.Capacity() == 30);
    s1.Erase(0,1);
    EXPECT_STREQ(s1.Data(), "234abcdefghia") << s1.Data();
    EXPECT_TRUE(s1.Size() == 13) << s1.Size();
    EXPECT_TRUE(s1.Capacity() == 30);

    s1.Erase(s1.Begin()+1);
    EXPECT_STREQ(s1.Data(), "24abcdefghia") << s1.Data();
    EXPECT_TRUE(s1.Size() == 12) << s1.Size();
    EXPECT_TRUE(s1.Capacity() == 30);

    s1.Erase(s1.Begin()+1, s1.End());
    EXPECT_STREQ(s1.Data(), "2") << s1.Data();
    EXPECT_TRUE(s1.Size() == 1) << s1.Size();
    EXPECT_TRUE(s1.Capacity() == 30);

    // push_back, pop_back
    s1 = "1234567890abcde";
    s1.ShrinkToFit();
    EXPECT_TRUE(s1.Capacity() == 15);
    EXPECT_TRUE(s1.Size() == 15);
    s1.PushBack('p');
    EXPECT_STREQ(s1.Data(), "1234567890abcdep");
    EXPECT_TRUE(s1.Capacity() == 30);
    EXPECT_TRUE(s1.Size() == 16);
    s1.PopBack();
    EXPECT_STREQ(s1.Data(), "1234567890abcde");
    EXPECT_TRUE(s1.Capacity() == 30);
    EXPECT_TRUE(s1.Size() == 15)<< s1.Size();
    // reSize
    s1.Resize(16);
    EXPECT_STREQ(s1.Data(), "1234567890abcde");
    EXPECT_TRUE(s1.Size() == 16)<< s1.Size();
    s1.Resize(10, 't');
    EXPECT_STREQ(s1.Data(), "1234567890");
    EXPECT_TRUE(s1.Size() == 10)<< s1.Size();
    s1.Resize(11, 't');
    EXPECT_STREQ(s1.Data(), "1234567890t");
    EXPECT_TRUE(s1.Size() == 11)<< s1.Size();
    // Capacity = 30

    // 替换Replace
    const char str[5] = "abcd";
    // len1 < len2
    s1.Replace(1, 3, str);
    EXPECT_STREQ(s1.Data(), "1abcd567890t");
    EXPECT_TRUE(s1.Size() == 12)<< s1.Size();
    EXPECT_TRUE(s1.Capacity() == 30);
    // len1 > len2
    s1.Replace(0, 5, str);
    EXPECT_STREQ(s1.Data(), "abcd567890t");
    EXPECT_TRUE(s1.Size() == 11)<< s1.Size();
    EXPECT_TRUE(s1.Capacity() == 30);
    // 重新分配内存
    s1.Append("12345");
    s1.ShrinkToFit();
    EXPECT_TRUE(s1.Capacity() == 16) << s1.Capacity(); 
    s1.Replace(15, 3, str);
    EXPECT_STREQ(s1.Data(), "abcd567890t1234abcd") << s1.Data();
    EXPECT_TRUE(s1.Size() == 19)<< s1.Size();
    EXPECT_TRUE(s1.Capacity() == 32);
    // init, iterator
    String s2 = "123456";
    s2.Replace(s2.Begin()+1, s2.Begin()+2, {'a','b','c'});
    EXPECT_STREQ(s2.Data(), "1abc3456") << s1.Data();
    s2.Replace(s2.Begin(), s2.Begin()+1, s1.Begin()+4, s1.Begin()+10);
    EXPECT_STREQ(s2.Data(), "567890abc3456") << s2.Data();
    EXPECT_TRUE(s2.Capacity() == 15);
    s2.Replace(s2.Begin()+3, s2.Begin()+6, str);
    EXPECT_STREQ(s2.Data(), "567abcdabc3456") << s2.Data();
    s2.Replace(s2.Begin(), s2.Begin()+10, s1);
    EXPECT_STREQ(s2.Data(), "abcd567890t1234abcd3456") << s2.Data();
    EXPECT_TRUE(s2.Capacity() == 30);
    String s3("12345");
    s3.Replace(1,0,"abc");
    EXPECT_STREQ(s3.Data(), "1abc2345") << s3.Data();

    // insert
    s3.Insert(1, "abc");
    EXPECT_STREQ(s3.Data(), "1abcabc2345") << s3.Data();
    s3.Insert(s3.Begin(), "b");
    EXPECT_STREQ(s3.Data(), "b1abcabc2345") << s3.Data();
    s3.Insert(s3.End(), String("poi"));
    EXPECT_STREQ(s3.Data(), "b1abcabc2345poi") << s3.Data();

    s3.Insert(s3.Begin()+1, s2.Begin()+3, s2.Begin()+6);
    EXPECT_STREQ(s3.Data(), "bd561abcabc2345poi") << s3.Data();
    s3.Insert(s3.Begin(), {'y','u','l'});
    EXPECT_STREQ(s3.Data(), "yulbd561abcabc2345poi") << s3.Data();

    /* swap */
    String s_local_buf1{""};
    String s_local_buf2{"1234567890abcde"};
    String s_alloc_buf1{"1234567890abcdef"};
    String s_alloc_buf2{"1234567890abcdefe"};

    // local swap local
    s_local_buf1.Swap(s_local_buf2);
    EXPECT_STREQ(s_local_buf1.Data(), "1234567890abcde");
    EXPECT_STREQ(s_local_buf2.Data(), "");
    EXPECT_TRUE(s_local_buf1.Capacity() == 15);
    EXPECT_TRUE(s_local_buf2.Capacity() == 15);
    EXPECT_TRUE(s_local_buf1.Size() == 15);
    EXPECT_TRUE(s_local_buf2.Size() == 0);

    // local swap alloc
    s_local_buf2.Swap(s_alloc_buf1);
    EXPECT_STREQ(s_alloc_buf1.Data(), "");
    EXPECT_TRUE(s_alloc_buf1.Capacity() == 15);
    EXPECT_TRUE(s_alloc_buf1.Size() == 0);
    EXPECT_STREQ(s_local_buf2.Data(), "1234567890abcdef");
    EXPECT_TRUE(s_local_buf2.Capacity() == 16) << s_local_buf2.Capacity();
    EXPECT_TRUE(s_local_buf2.Size() == 16);

    // alloc swap local
    s_local_buf2.Swap(s_alloc_buf1);
    EXPECT_STREQ(s_alloc_buf1.Data(), "1234567890abcdef");
    EXPECT_TRUE(s_alloc_buf1.Capacity() == 16);
    EXPECT_TRUE(s_alloc_buf1.Size() == 16);
    EXPECT_STREQ(s_local_buf2.Data(), "");
    EXPECT_TRUE(s_local_buf2.Capacity() == 15) << s_local_buf2.Capacity();
    EXPECT_TRUE(s_local_buf2.Size() == 0);

    // alloc swap alloc
    s_alloc_buf1.Swap(s_alloc_buf2);
    EXPECT_STREQ(s_alloc_buf1.Data(), "1234567890abcdefe");
    EXPECT_TRUE(s_alloc_buf1.Capacity() == 17) << s_alloc_buf1.Capacity();
    EXPECT_TRUE(s_alloc_buf1.Size() == 17);
    EXPECT_STREQ(s_alloc_buf2.Data(), "1234567890abcdef");
    EXPECT_TRUE(s_alloc_buf2.Capacity() == 16) << s_alloc_buf2.Capacity();
    EXPECT_TRUE(s_alloc_buf2.Size() == 16);

    /* compare */
    String no{};
    String big{"123456"};
    String small{"12345"};
    const char t[6] = "12345";
    String equ{"12345"};
    EXPECT_TRUE(small.Compare(equ) == 0);
    EXPECT_TRUE(small.Compare(t) == 0);
    EXPECT_TRUE(small.Compare(no) == 1) << small.Compare(no);
    EXPECT_TRUE(small.Compare("") == 1) << small.Compare("");
    EXPECT_TRUE(small.Compare(big) == -1) << big.Compare(small);
    EXPECT_TRUE(big.Compare(t) == 1) << big.Compare(t);

    /* substr */
    String sub = small.Substr();
    EXPECT_STREQ(sub.Data(), "12345") << sub.Data();
    String sub1 = small.Substr(1,4);
    EXPECT_STREQ(sub1.Data(), "2345") << sub1.Data();
    String sub2 = small.Substr(1,0);
    EXPECT_STREQ(sub2.Data(), "") << sub2.Data();
    String sub3 = small.Substr(4,1);
    EXPECT_STREQ(sub3.Data(), "5") << sub3.Data();
}

TEST(StringTest, nomodfiy) {
    // begin, end
    String s0("1234567890abcdef");
    const String s1("1234567890abcdef");
    EXPECT_TRUE(*s0.Begin() == '1');
    EXPECT_TRUE(*(--s0.End()) == 'f');

    EXPECT_TRUE(*s1.Begin() == '1');
    testing::StaticAssertTypeEq<decltype(*s1.Begin()), const char&>();

    EXPECT_TRUE(*(--s1.End()) == 'f');

    EXPECT_TRUE(*s0.Cbegin() == '1');
    testing::StaticAssertTypeEq<decltype(*s0.Cbegin()), const char&>();
    //empty
    String s2;
    EXPECT_TRUE(s2.Empty());
    s0 = "";
    EXPECT_TRUE(s0.Empty());
    s0 = "1234";
    s0.Assign("");
    EXPECT_TRUE(s0.Empty());
    s0 = "1234";
    s0 = s2;
    EXPECT_TRUE(s0.Empty());

    //Data
    String s3("12345");
    const String s4("12345");
    testing::StaticAssertTypeEq<decltype(s3.Data()), char*>();
    testing::StaticAssertTypeEq<decltype(s4.Data()), const char*>();
    //front
    s3.Front() = 'b';
    EXPECT_STREQ(s3.Data(), "b2345");
    testing::StaticAssertTypeEq<decltype(s4.Front()), const char&>();
    //back
    s3.Back() = 'a';
    EXPECT_STREQ(s3.Data(), "b234a");
    testing::StaticAssertTypeEq<decltype(s4.Back()), const char&>();

    // copy
    char bar[4]{};
    s3.Copy(bar, 2, 2);
    EXPECT_STREQ(bar, "34");
    s3.Copy(bar, sizeof bar - 1);
    EXPECT_STREQ(bar, "b23");

    // clear
    s3.Clear();
    EXPECT_STREQ(s3.Data(), "");
    EXPECT_TRUE(s3.Capacity() == 15);
    EXPECT_TRUE(s3.Size() == 0);
    EXPECT_TRUE(s3.Empty());

    s0.Clear();
    EXPECT_STREQ(s0.Data(), "");
    EXPECT_TRUE(s0.Capacity() == 16);
    EXPECT_TRUE(s0.Size() == 0);
    EXPECT_TRUE(s0.Empty());
    // const 字符串不能clear
    // s1.clear();
}

TEST(StringTest, Capacity) {
    String s0;
    String s1("1234567890abcdef");
    // reserve
    s0.Reserve();
    EXPECT_TRUE(s0.Capacity() == 15);
    s0.Reserve(3);
    EXPECT_TRUE(s0.Capacity() == 15);
    s0.Reserve(16);
    EXPECT_TRUE(s0.Capacity() == 30);
    s0.Reserve(3);
    EXPECT_TRUE(s0.Capacity() == 15);
    s1.Reserve();
    EXPECT_TRUE(s1.Capacity() == 16);
    s1.Reserve(16);
    EXPECT_TRUE(s1.Capacity() == 16);
    s1.Reserve(17);
    EXPECT_TRUE(s1.Capacity() == 32);

    s1 = "1234567890abcdef123";
    EXPECT_TRUE(s1.Capacity() == 32);
    EXPECT_TRUE(s1.Size() == 19);
    s1.Reserve();
    EXPECT_TRUE(s1.Capacity() == 19);
    EXPECT_TRUE(s1.Size() == 19);

    s1 = "123";
    EXPECT_TRUE(s1.Capacity() == 19);
    EXPECT_TRUE(s1.Size() == 3);
    s1.Reserve();
    EXPECT_TRUE(s1.Capacity() == 15);
    EXPECT_TRUE(s1.Size() == 3);

    // shrink_to_fit
    s1.ShrinkToFit();
    EXPECT_TRUE(s1.Capacity() == 15);
    EXPECT_TRUE(s1.Size() == 3);
    s1 = "1234567890abcdef123";
    s1 = "1234567890abcdef";
    EXPECT_TRUE(s1.Capacity() == 19) << s1.Capacity();
    EXPECT_TRUE(s1.Size() == 16);
    s1.ShrinkToFit();
    EXPECT_TRUE(s1.Capacity() == 16);
    EXPECT_TRUE(s1.Size() == 16);
    s1 = "123";
    s1.ShrinkToFit();
    EXPECT_TRUE(s1.Capacity() == 15);
    EXPECT_TRUE(s1.Size() == 3);
}
